package com.demo.config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.ServletContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.util.UrlPathHelper;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;

@Configuration
@EnableWebMvc
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ComponentScan(value = { "com.demo" }, includeFilters = { @Filter({ Controller.class, RestController.class }) })
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {

	/**
	 * @see org.springframework.format.support.FormattingConversionServiceFactoryBean
	 */
	@Override
	public void addFormatters(FormatterRegistry registry) {}

	/**
	 * mvc:annotation-driven
	 */
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		converters.add(fastJsonHttpMessageConverter4());
	}

	/**
	 * mvc:annotation-driven
	 */
	@Override
	public Validator getValidator() {
		// return "global" validator
		return null;
	}

	/**
	 * @see org.springframework.web.accept.ContentNegotiationManagerFactoryBean
	 */
	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
		configurer.ignoreAcceptHeader(true);
		configurer.favorParameter(true);
		configurer.favorPathExtension(true);
		configurer.defaultContentType(MediaType.TEXT_HTML);

		Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>();
		mediaTypes.put("xml", MediaType.APPLICATION_XML);
		mediaTypes.put("json", MediaType.TEXT_PLAIN);
		mediaTypes.put("xls", MediaType.valueOf("application/vnd.ms-excel"));
		configurer.mediaTypes(mediaTypes);
	}

	/**
	 * <mvc:annotation-driven> has an <async-support>
	 */
	@Override
	public void configureAsyncSupport(AsyncSupportConfigurer configurer) {}

	/**
	 *
		<mvc:annotation-driven>
		    <mvc:path-matching
		        suffix-pattern="true"
		        trailing-slash="false"
		        registered-suffixes-only="true"
		        path-helper="pathHelper"
		        path-matcher="pathMatcher"/>
		</mvc:annotation-driven> 
	 */
	@Override
	public void configurePathMatch(PathMatchConfigurer configurer) {
		configurer.setUseSuffixPatternMatch(true)//
				.setUseTrailingSlashMatch(false)//
				.setUseRegisteredSuffixPatternMatch(true)//
				.setPathMatcher(antPathMatcher())//
				.setUrlPathHelper(urlPathHelper());
	}

	/**
	 * 添加拦截器
	 */
	@Override
	public void addInterceptors(InterceptorRegistry registry) {}

	/**
	 * mvc:view-resolvers
	 */
	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.jsp("/WEB-INF/views/", ".jsp");
		registry.enableContentNegotiation(fastJsonJsonView());
	}

	/**
	 * mvc:resources
	 */
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/images/**").addResourceLocations("/WEB-INF/images/");
		registry.addResourceHandler("/css/**").addResourceLocations("/WEB-INF/css/");
		registry.addResourceHandler("/js/**").addResourceLocations("/WEB-INF/js/");
	}

	/**
	 * XML:<mvc:default-servlet-handler/>
	 */
	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}

	@Override
	public void addCorsMappings(CorsRegistry registry) {
		// Global CORS configuration
	}

	/**
	 * mvc:view-controller
	 */
	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		// TODO 配置错误页面和首页重定向
		//		registry.addRedirectViewController("/", "/index.html");// 重定向首页
		//		registry.addStatusController("", HttpStatus.NOT_FOUND);// 404
		//		registry.addStatusController("", HttpStatus.INTERNAL_SERVER_ERROR);// 500
	}

	/**
	 * 定义异常处理页面
	 */
	@Override
	public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
		//		exceptionResolvers.add(exceptionResolver());
	}

	// ----------------------------------
	// bean
	// ----------------------------------
	public HandlerExceptionResolver exceptionResolver() {
		SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
		Properties mappings = new Properties();
		// key --> *Exception , value --> view
		mappings.setProperty("java.sql.SQLException", "outException");
		mappings.setProperty("java.io.IOException", "outException");
		exceptionResolver.setExceptionMappings(mappings);
		return exceptionResolver;
	}

	@Bean
	public View fastJsonJsonView() {
		FastJsonJsonView view = new FastJsonJsonView();
		view.setContentType("text/plain");
		return view;
	}

	@Bean
	public FastJsonHttpMessageConverter4 fastJsonHttpMessageConverter4() {
		FastJsonHttpMessageConverter4 converter = new FastJsonHttpMessageConverter4();

		List<MediaType> mediaTypes = new ArrayList<MediaType>();
		mediaTypes.add(MediaType.valueOf("text/html;charset=UTF-8"));
		mediaTypes.add(MediaType.valueOf("application/json"));
		converter.setSupportedMediaTypes(mediaTypes);

		List<SerializerFeature> features = new ArrayList<SerializerFeature>();
		features.add(SerializerFeature.WriteMapNullValue);
		features.add(SerializerFeature.QuoteFieldNames);
		features.add(SerializerFeature.UseISO8601DateFormat);
		converter.getFastJsonConfig().setSerializerFeatures(features.toArray(new SerializerFeature[features.size()]));

		return new FastJsonHttpMessageConverter4();
	}

	@Bean
	@Autowired
	public CommonsMultipartResolver multipartResolver(ServletContext servletContext) {
		CommonsMultipartResolver resolver = new CommonsMultipartResolver(servletContext);
		resolver.setDefaultEncoding("UTF-8");
		resolver.setMaxUploadSize(1024L * 1024 * 1024 * 100);
		return resolver;
	}

	@Bean
	public UrlPathHelper urlPathHelper() {
		return new UrlPathHelper();
	}

	@Bean
	public PathMatcher antPathMatcher() {
		return new AntPathMatcher();
	}
}